#region
/* Adoor.NET - Object/Relational mapping framework leveraging ADO.NET`s powerful disconnected mode.
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *  
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *  
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */ 
#endregion

using System;
using System.Diagnostics;
using Adoor.Expression;
using Adoor.Expression.AST;
using Adoor.Object.Domain;
using Adoor.Object.Query;
using System.Collections.Generic;

namespace Adoor.Object.Relational
{
	/// <summary>
	/// Summary description for ExpressionExpander.
	/// </summary>
	public class ExpressionExpander: ExpressionCloner
	{
		private List<SelectExpression> listResult;
		private MappingStrategyEnum mappingKind;

		public static ExpressionNode Evaluate(ExpressionNode n, ObjectPath context, MappingStrategyEnum mappingKind, out IList<SelectExpression> newColumns)
		{
			ExpressionExpander es = new ExpressionExpander(context, mappingKind);
			n.Accept(es);
			newColumns = es.listResult;
			return es.result;
		}

		protected ObjectPath context;

		protected ExpressionExpander(ObjectPath context, MappingStrategyEnum mappingKind)
		{
			this.context = context;
			this.mappingKind = mappingKind;
            this.listResult = new List<SelectExpression>();
		}

		public override void VisitName(ExpressionName n)
		{	
			if(n.Value.StartsWith("@"))
				return;

			if (n.Qualifier == "")
			{
				string name = n.Value;
				Correlation s = (Correlation)context.Correlations[name];
				if (s == null)
					throw new Exception("invalid column " + name + " : column names should be either the name of an alias as defined in the from clause, in which case it represents the oid of the entity, or the name of a property, qualified by an alias (i.e. \"alias.property\")");

				IEntityMappingStrategyProvider provider = (IEntityMappingStrategyProvider) s.EntityData.GetService(typeof(IEntityMappingStrategyProvider));
				IEntityMappingStrategy mappingStrategy = provider.GetMappingStrategy(mappingKind);
//				if(mappingKind == MappingStrategyEnum.Remote2)
//				{
//					SelectExpression[] oids = mappingStrategy.KeyMappingStrategy.GetKeySelectExpression(n.Qualifier);
//					listResult.AddRange(oids);
//				}
//				else
				this.result = mappingStrategy.KeyMappingStrategy.GetOidExpression(name);
			}
			else if (n.Value == "*")
			{
				Correlation s = (Correlation)context.Correlations[n.Qualifier];
				IEntityMappingStrategyProvider provider = (IEntityMappingStrategyProvider)s.EntityData.GetService(typeof(IEntityMappingStrategyProvider));
				IEntityMappingStrategy mappingStrategy = provider.GetMappingStrategy(mappingKind);
//				if(mappingKind == MappingStrategyEnum.Remote2)
//				{
//					SelectExpression[] oids = mappingStrategy.KeyMappingStrategy.GetKeySelectExpression(n.Qualifier);
//					listResult.AddRange(oids);
//				}
//				else
//				{
				ExpressionName[] rc = mappingStrategy.KeyMappingStrategy.GetKeyColumns(n.Qualifier);
				if (rc.Length != 1)
					throw new Exception("compound keys cannot be specified in select clause");
				this.result = rc[0];
//				}
				foreach(PropertyData pf in s.EntityData.PropertyInfos.Values)
				{
					IPropertyMappingStrategy strategy = (IPropertyMappingStrategy)pf.GetService(typeof(IPropertyMappingStrategy));
					strategy.InsertRelationalColumn(listResult, n.Qualifier);
				}
			}
			else 
			{
				base.VisitName(n);
			}
		}
	}
}
